﻿namespace Silverlight.Treemap
{
    using System;
    using System.Collections;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Diagnostics.CodeAnalysis;
    using System.Windows;
    using System.Windows.Controls;

    using Controls.DataVisualization.Toolkit.Charting;

    using Extensions;

    [TemplatePart(Name = WorkAreaName, Type = typeof(Canvas))]
    [StyleTypedProperty(Property = "FolderStyle", StyleTargetType = typeof(Canvas))]
    [StyleTypedProperty(Property = "FileStyle", StyleTargetType = typeof(Canvas))]
    public class ChartSector : Control, IGetTemplateChild
    {
        #region public Style FolderStyle

        /// <summary>
        /// Identifies the LegendStyle dependency property.
        /// </summary>
        public static readonly DependencyProperty FolderStyleProperty = DependencyProperty.Register(
                "FolderStyle", typeof(Style), typeof(ChartSector), null);

        /// <summary>
        /// Gets or sets the Style of the ISeriesHost's Legend.
        /// </summary>
        public Style FolderStyle
        {
            get { return this.GetValue(FolderStyleProperty) as Style; }
            set { this.SetValue(FolderStyleProperty, value); }
        }

        #endregion public Style FolderStyle

        #region public Style FileStyle

        /// <summary>
        /// Identifies the LegendStyle dependency property.
        /// </summary>
        public static readonly DependencyProperty FileStyleProperty = DependencyProperty.Register(
                "FileStyle", typeof(Style), typeof(ChartSector), null);

        /// <summary>
        /// Gets or sets the Style of the ISeriesHost's Legend.
        /// </summary>
        public Style FileStyle
        {
            get { return this.GetValue(FileStyleProperty) as Style; }
            set { this.SetValue(FileStyleProperty, value); }
        }

        #endregion public Style FileStyle

        #region public Collection<Style> StylePalette

        /// <summary>
        /// Identifies the StylePalette dependency property.
        /// </summary>
        public static readonly DependencyProperty StylePaletteProperty = DependencyProperty.Register(
                "StylePalette",
                typeof(Collection<Style>),
                typeof(ChartSector),
                new PropertyMetadata(OnStylePalettePropertyChanged));

        /// <summary>
        /// Gets or sets a palette of styles used by the children of the ISeriesHost.
        /// </summary>
        [SuppressMessage("Microsoft.Usage", "CA2227:CollectionPropertiesShouldBeReadOnly",
                Justification = "Want to allow this to be set from XAML.")]
        public Collection<Style> StylePalette
        {
            get { return this.GetValue(StylePaletteProperty) as Collection<Style>; }
            set { this.SetValue(StylePaletteProperty, value); }
        }

        /// <summary>
        /// Called when the value of the StylePalette property is changed.
        /// </summary>
        /// <param name="d">Chart that contains the changed StylePalette.
        /// </param>
        /// <param name="e">Event arguments.</param>
        private static void OnStylePalettePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
            var source = (ChartSector)d;
            var newValue = (Collection<Style>)e.NewValue;
            source.OnStylePalettePropertyChanged(newValue);
        }

        /// <summary>
        /// Called when the value of the StylePalette property is changed.
        /// </summary>
        /// <param name="newValue">The new value for the StylePalette.</param>
        private void OnStylePalettePropertyChanged(Collection<Style> newValue)
        {
            this.StyleDispenser.Styles = newValue;
            this.ResetStyles();
            //Refresh the styles
            //foreach (Series series in this.Series)
            //{
            //    series.RefreshStyles();
            //}
        }

        #endregion public Collection<Style> StylePalette

        private const string WorkAreaName = "ChildWorkArea";

        public static readonly DependencyProperty ChildItemsSourceProperty =
                DependencyProperty.Register(
                        "ChildItemsSource",
                        typeof(IEnumerable),
                        typeof(ChartSector),
                        new PropertyMetadata(OnChildItemsSourceChanged));

        /// <summary>
        /// Identifies the DependentValue dependency property.
        /// </summary>
        public static readonly DependencyProperty DependentValueProperty = DependencyProperty.Register(
                "DependentValue",
                typeof(double),
                typeof(ChartSector),
                new PropertyMetadata(0.0, OnDependentValuePropertyChanged));

        /// <summary>
        /// Identifies the IndependentValue dependency property.
        /// </summary>
        public static readonly DependencyProperty IndependentValueProperty =
                DependencyProperty.Register(
                        "IndependentValue",
                        typeof(string),
                        typeof(ChartSector),
                        new PropertyMetadata(string.Empty, OnIndependentValuePropertyChanged));

        public ChartSector()
        {
            this.DefaultStyleKey = typeof(ChartSector);
            // Create style dispenser
            this.StyleDispenser = new StyleDispenser();
            this.ChildChartSectors = new List<ChartSector>();
        }

        public static int StylePalattePicker
        {
            get;
            set;
        }

        public static bool StyleApplied
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets an object that rotates through the palette.
        /// </summary>
        private StyleDispenser StyleDispenser
        {
            get;
            set;
        }

        public double Area
        {
            get;
            set;
        }

        /// <summary>
        /// Gets or sets the independent value.
        /// </summary>
        public string IndependentValue
        {
            get { return (string)this.GetValue(IndependentValueProperty); }
            set { this.SetValue(IndependentValueProperty, value); }
        }

        /// <summary>
        /// Gets or sets the dependent value of the Control.
        /// </summary>
        public double DependentValue
        {
            get { return (double)this.GetValue(DependentValueProperty); }
            set { this.SetValue(DependentValueProperty, value); }
        }

        public IEnumerable ChildItemsSource
        {
            get { return (IEnumerable)this.GetValue(ChildItemsSourceProperty); }
            set { this.SetValue(ChildItemsSourceProperty, value); }
        }

        public List<ChartSector> ChildChartSectors
        {
            get;
            set;
        }

        public double Percentage
        {
            get;
            set;
        }

        public Canvas WorkAreaCanvas
        {
            get;
            set;
        }

        #region IGetTemplateChild Members

        public DependencyObject GetTemplateChildHelper(string childName)
        {
            return this.GetTemplateChild(childName);
        }

        #endregion

        /// <summary>
        /// Returns a rotating enumerator of Style objects that coordinates with 
        /// the style dispenser object to ensure that no two enumerators are
        /// currently on the same style if possible.  If the style
        /// dispenser is reset or its collection of styles is changed then
        /// the enumerators will also be reset.
        /// </summary>
        /// <param name="stylePredicate">A predicate that returns a value
        /// indicating whether to return a style.</param>
        /// <returns>An enumerator of styles.</returns>
        public IEnumerator<Style> GetStylesWhere(Func<Style, bool> stylePredicate)
        {
            return this.StyleDispenser.GetStylesWhere(stylePredicate);
        }

        /// <summary>
        /// Resets the styles dispensed by the chart.
        /// </summary>
        public void ResetStyles()
        {
            this.StyleDispenser.ResetStyles();
        }

        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            this.WorkAreaCanvas = this.GetTemplateChild<Canvas>(WorkAreaName);
            this.WorkAreaCanvas.SizeChanged += this.WorkAreaCanvas_OnSizeChanged;

            //if (this.WorkAreaCanvas != null)
            //{
            //    if (StylePalattePicker == this.StyleDispenser.Styles.Count)
            //    {
            //        StylePalattePicker = 0;
            //    }

            //    this.WorkAreaCanvas.Style = this.StyleDispenser.Styles[StylePalattePicker];
            //    StylePalattePicker++;
            //    Debug.WriteLine(StylePalattePicker);
            //    StyleApplied = true;
            //}
            if (StylePalattePicker == this.StyleDispenser.Styles.Count)
            {
                StylePalattePicker = 0;
            }
            this.WorkAreaCanvas.Style = this.IndependentValue.ToUpper().Contains("FOLDER")
                                                ? this.StyleDispenser.Styles[StylePalattePicker]
                                                : this.StyleDispenser.Styles[StylePalattePicker];
            StylePalattePicker++;
        }

        protected override Size MeasureOverride(Size availableSize)
        {
            return base.MeasureOverride(availableSize);
        }

        protected override Size ArrangeOverride(Size finalSize)
        {
            return base.ArrangeOverride(finalSize);
        }

        private static void OnDependentValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
        }

        private static void OnIndependentValuePropertyChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
        }

        private static void OnChildItemsSourceChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
        {
        }

        private void WorkAreaCanvas_OnSizeChanged(object sender, SizeChangedEventArgs e)
        {
            if (this.ChildChartSectors.Count > 0 & e.NewSize.Width > 0 && e.NewSize.Height > 0)
            {
                this.ChildChartSectors = Plotter.Plot(this.ChildChartSectors, e.NewSize);
                this.WorkAreaCanvas.Children.Clear();
                this.ChildChartSectors.ForEach(sector => this.WorkAreaCanvas.Children.Add(sector));
            }
        }
    }
}